const Sequelize = require('sequelize');
const moment = require('moment');
const Op = Sequelize.Op;
const db = require('../model/index');
const Equipment = db.models.Equipment;
const EquipmentAttribute = db.models.EquipmentAttribute;
const InspectionFile = db.models.InspectionFile;
const InspectionRecord = db.models.InspectionRecord;
const { removeEmpty } = require('../lib/utilx');


class InspectionController {
  async getInsFileList(ctx) {
    let { page, limit, sStr, sType, sTime } = ctx.request.body;
    let where = {};
    // 不能同时有两个[Op.or]，因此不能用assign，但是不同的search字段之间是and关系
    if(sStr && sTime) {
      where = Object.assign(where, {
        [Op.and] : [{
          [Op.or]: [{
            oid: {
              [Op.like]: `%${sStr}%`,
            }
          },{
            title: {
              [Op.like]: `%${sStr}%`,
            }
          },{
            daySignatory: {
              [Op.like]: `%${sStr}%`,
            }
          },{
            nightSignatory: {
              [Op.like]: `%${sStr}%`,
            }
          },{
            superSignatory: {
              [Op.like]: `%${sStr}%`,
            }
          }]
        },{
          [Op.or] : [{
            type: 'it',
            createdAt: {  // 又忘记* 1000了
              [Op.gte]: new Date(moment.unix(sTime).startOf('week').unix() * 1000),
              [Op.lte] : new Date(moment.unix(sTime).endOf('week').unix() * 1000),
            }
          },{
            type: 'workstation',
            createdAt: {  // 又忘记* 1000了
              [Op.gte]: new Date(moment.unix(sTime).startOf('week').unix() * 1000),
              [Op.lte] : new Date(moment.unix(sTime).endOf('week').unix() * 1000),
            }
          },{
            type: 'oracle',
            createdAt: {
              [Op.gte]: new Date(moment.unix(sTime).startOf('day').unix() * 1000),
              [Op.lte] : new Date(moment.unix(sTime).endOf('day').unix() * 1000),
            }
          },{
            type: 'bnw',
            createdAt: {
              [Op.gte]: new Date(moment.unix(sTime).startOf('day').unix() * 1000),
              [Op.lte] : new Date(moment.unix(sTime).endOf('day').unix() * 1000),
            }
          },{
            type: 'bhics',
            createdAt: {
              [Op.gte]: new Date(moment.unix(sTime).startOf('day').unix() * 1000),
              [Op.lte] : new Date(moment.unix(sTime).endOf('day').unix() * 1000),
            }
          },{
            type: 'bhics2',
            createdAt: {
              [Op.gte]: new Date(moment.unix(sTime).startOf('day').unix() * 1000),
              [Op.lte] : new Date(moment.unix(sTime).endOf('day').unix() * 1000),
            }
          }]
        }]
      });
    } else if (sStr) {
      where = Object.assign(where, {
        [Op.or]: [{
          oid: {
            [Op.like]: `%${sStr}%`,
          }
        },{
          title: {
            [Op.like]: `%${sStr}%`,
          }
        },{
          daySignatory: {
            [Op.like]: `%${sStr}%`,
          }
        },{
          nightSignatory: {
            [Op.like]: `%${sStr}%`,
          }
        },{
          superSignatory: {
            [Op.like]: `%${sStr}%`,
          }
        }]
      });
    } else if(sTime) {
      where = Object.assign(where, {
        [Op.or]: [{
          type: 'it',
          createdAt: {  // 又忘记* 1000了
            [Op.gte]: new Date(moment.unix(sTime).startOf('week').unix() * 1000),
            [Op.lte] : new Date(moment.unix(sTime).endOf('week').unix() * 1000),
          }
        },{
          type: 'workstation',
          createdAt: {  // 又忘记* 1000了
            [Op.gte]: new Date(moment.unix(sTime).startOf('week').unix() * 1000),
            [Op.lte] : new Date(moment.unix(sTime).endOf('week').unix() * 1000),
          }
        },{
          type: 'oracle',
          createdAt: {
            [Op.gte]: new Date(moment.unix(sTime).startOf('day').unix() * 1000),
            [Op.lte] : new Date(moment.unix(sTime).endOf('day').unix() * 1000),
          }
        },{
          type: 'bnw',
          createdAt: {
            [Op.gte]: new Date(moment.unix(sTime).startOf('day').unix() * 1000),
            [Op.lte] : new Date(moment.unix(sTime).endOf('day').unix() * 1000),
          }
        },{
          type: 'bhics',
          createdAt: {
            [Op.gte]: new Date(moment.unix(sTime).startOf('day').unix() * 1000),
            [Op.lte] : new Date(moment.unix(sTime).endOf('day').unix() * 1000),
          }
        },{
          type: 'bhics2',
          createdAt: {
            [Op.gte]: new Date(moment.unix(sTime).startOf('day').unix() * 1000),
            [Op.lte] : new Date(moment.unix(sTime).endOf('day').unix() * 1000),
          }
        }]
      });
    }
    if( sType !== '全部' ) {
      where = Object.assign(where, {
        type: sType,
      });
    }
    where = removeEmpty(where);

    let totalCount = await InspectionFile.count({
      where,
    });
    let inspectionList = await InspectionFile.findAll({
      where,
      limit: limit === -1 ? undefined : limit,
      offset: limit === -1 ? undefined: (page - 1) * limit,
      order: [
        ['createdAt', 'DESC']
      ]
    });
    inspectionList = inspectionList.map((file) => {
      if( file.type === 'it' || file.type === 'workstation') {  // 如果是周检查单，返回一周的签字数据
        return Object.assign(file.dataValues, {
          signatory: [
            file.d1Signatory || '',
            file.n1Signatory || '',

            file.d2Signatory || '',
            file.n2Signatory || '',

            file.d3Signatory || '',
            file.n3Signatory || '',

            file.d4Signatory || '',
            file.n4Signatory || '',

            file.d5Signatory || '',
            file.n5Signatory || '',

            file.d6Signatory || '',
            file.n6Signatory || '',

            file.d7Signatory || '',
            file.n7Signatory || '',

            file.superSignatory || '',
          ]
        });
      } else {   // 如果是日检查单
        return Object.assign(file.dataValues, {
          signatory: [
            file.daySignatory || '',
            file.nightSignatory || '',
            file.superSignatory || '',
          ]
        });
      }
    });

    ctx.body = {
      code: 0,
      msg: {
        total: totalCount,
        inspectionList,
      }
    }
  }

  async addInsFile(ctx) {
    let { type, title, createdAt } = ctx.request.body;
    let index = await InspectionFile.count({
      where: {
        createdAt: {
          [Op.gte]: new Date(moment().startOf('year').unix() * 1000),
          [Op.lte]: new Date(moment().endOf('year').unix() * 1000),
        }
      }
    });
    await InspectionFile.create({
      oid: index,
      createdTime: true,
      title,
      type,
      isAbnormal: false,
      createdAt: new Date(createdAt * 1000)
    });
    ctx.body = {
      code: 0,
      msg: {},
    }
  }

  async deleteInsFile(ctx) {
    let { oid } = ctx.request.body;
    await InspectionRecord.destroy({
      where: {
        InspectionFileOid: oid,
      }
    });
    await InspectionFile.destroy({
      where: {
        oid,
      }
    });
    ctx.body = {
      code: 0,
      msg: {},
    }
  }

  /**
   * 这样写这个函数太耗内存了
   */
  async getDayInspectionRecordList(ctx) {
    let { oid } = ctx.request.body;
    let file = await InspectionFile.findOne({
      where: {
        oid,
      }
    });
    if(!file) {
      ctx.body = {
        code: 9,
        msg: {
          error: '不存在此巡视检查单',
        }
      };
      return;
    }

    /**
     * 根据EquipmentId和value排好序，InspectionRecords的长度肯定是1（被Oid和EquipmentAttributeId同时限定），这样就得到以EquipmentAttribute分行的数据
     * 每日巡视数据用这种方法查询会更简单吧
     */
    // let records = await EquipmentAttribute.scope('all').findAll({
    //   order: [
    //     ['value', 'ASC'],
    //     ['EquipmentId', 'ASC']
    //   ],
    //   include: [{
    //     model: InspectionRecord,
    //     where: {
    //       InspectionFileOid: file.oid,
    //       EquipmentAttributeId: db.col('EquipmentAttribute.id')
    //     },
    //   }, {
    //     model: Equipment.scope('all'),
    //     where: {
    //       type: file.type,
    //     },
    //     attributes: ['id', 'name', 'label', 'scope', 'radios'],
    //   }]
    // });

    let inspectionRecords = [];
    let records = await InspectionRecord.findAll({
      where: {
        InspectionFileOid: oid,
      },
      include: [{
        model: EquipmentAttribute.scope('all'),
        include: [{
          model: Equipment.scope('all'),
          where: {   // 更改设备会有很多问题，比如这里更改设备所属检查单就会出问题，所以只能不允许修改设备
            type: file.type,
          },
          attributes: ['id', 'name', 'label', 'scope', 'radios', 'createdAt'],
        }]
      }]
    });
    if( file.type === 'it' || file.type === 'workstation' ) {  // 如果是周检查单
      ctx.body = {
        code: 10,
        msg: {
          error: '请求接口错误',
        }
      };
      return;
    } else {  // 如果是日检查单
      let hours = [];
      let counters = [];  // 计算某个hour共有多少个record
      records = records.map((record) => {
        let hour = record.EquipmentAttribute.value;
        if (hours.indexOf(hour) === -1) {
          hours.push(hour);
        }
        if(counters[hour * 10] !== null && counters[hour * 10] !== undefined) {  // todo: 又被0为false给坑了
          counters[hour * 10] += 1;
        } else {
          counters[hour * 10] = 1;  // 跑到这里说明已经有了一个元素，应该是1而不是0
        }
        return {
          id: record.id,
          EquipmentId: record.EquipmentAttribute.Equipment.id,
          equipmentState: record.state,
          equipmentName: record.EquipmentAttribute.Equipment.name,
          hour: record.EquipmentAttribute.value,
        }
      });
      hours.sort((a, b) => {  // 按hour从小到大排序
        return a > b ? 1 : -1;
      });
      records.sort((a, b) => {  // 按hour从小到大排序
        return a.hour > b.hour ? 1 : -1;
      });
      let sum = 0;
      counters = counters.map((count, idx) => {   // 将counter数组各元素转换为加和
        sum += count;
        return sum;
      });
      for( let i=0; i<hours.length; i+=1 ) {   // 按照hour的不同分成不同的数组
        let hour = hours[i];
        let start = i === 0 ? 0 : counters[hours[i - 1] * 10];
        let end = counters[hour * 10];
        inspectionRecords.push({
          hour,
          inspectionTime: Math.floor(hour) === hour ? `${hour}:00` : `${Math.floor(hour)}:30`,
          records: records.slice(start, end),
        });
      }
    }

    let startHour;   // 日检查单的记录从几点开始
    switch(file.type) {
      case 'oracle':
        startHour = 8;
        break;
      case 'bnw':
        startHour = 8;
        break;
      case 'bhics':
        startHour = 9;
        break;
      case 'bhics2':
        startHour = 0;
        break;
      default:
        startHour = 0;
    }

    let splitIndex;
    inspectionRecords.forEach((r, i) => {
      if( r.hour === startHour ) {  // 找到了分割点
        splitIndex = i;
      }
    });
    if(splitIndex) {  // 为0则同样不需要做处理
      let a = inspectionRecords.slice(0, splitIndex);
      let b = inspectionRecords.slice(splitIndex);
      inspectionRecords = b.concat(a);
    }

    ctx.body = {
      code: 0,
      msg: {
        createdAt: new Date(file.createdAt).getTime(),
        daySignatory: file.daySignatory,
        nightSignatory: file.nightSignatory,
        superSignatory: file.superSignatory,
        abnormalRecord: file.abnormalRecord,
        totalCount: inspectionRecords.length,
        count: inspectionRecords.length,
        inspectionRecords,
      }
    }
  }

  async getWeekInspectionRecordList(ctx) {
    let { oid } = ctx.request.body;
    let file = await InspectionFile.findOne({
      where: {
        oid,
      }
    });
    if(!file) {
      ctx.body = {
        code: 9,
        msg: {
          error: '不存在此巡视检查单',
        }
      };
      return;
    }

    if( file.type === 'it' || file.type === 'workstation' ) {  // 如果是周检查单
      /**
       * 按照设备分好行
       */
      let attributes = await EquipmentAttribute.scope('all').findAll({  // 根据id排序自然就是根据创建时间排序了，如果想要顺序可控，可以加一个字段
        order: [
          ['EquipmentId', 'ASC']
        ],
        include: [{
          model: InspectionRecord,
          where: {
            InspectionFileOid: file.oid,
            EquipmentAttributeId: db.col('EquipmentAttribute.id')
          }
        }, {
          model: Equipment.scope('all'),
          where: {
            type: file.type,
          },
          attributes: ['id', 'name', 'label', 'scope', 'radios', 'createdAt'],
        }]
      });

      let inspectionRecords = [];
      let EquipmentId;
      attributes.forEach((attribute, idx) => {
        if(EquipmentId !== attribute.EquipmentId) {  // 由于已经按照EquipmentId排序，如果设备不同了，那么说明要另起一行
          EquipmentId = attribute.EquipmentId;
          inspectionRecords.push({
            id: attribute.Equipment.id,
            EquipmentId,
            equipmentName: attribute.Equipment.name,
            scope: attribute.Equipment.scope,
            equipmentState: [],
          });
        }
        // 加入equipmentState
        inspectionRecords[inspectionRecords.length - 1].equipmentState.push({
          id: attribute.InspectionRecords[0].id,
          weekday: attribute.value,
          state: attribute.InspectionRecords[0].state,
          label: attribute.Equipment.label,
        });
      });

      // 设置scopes并将记录按序排好
      let scopes = [];
      inspectionRecords.forEach((r) => {
        let pushFlag = true;
        scopes.forEach((s) => {
          if(s.scopeName === r.scope) {   // 如果有相同的
            pushFlag = false;
            s.scopeCount += 1;
          }
        });
        if(pushFlag) {
          scopes.push({
            scopeName: r.scope,
            scopeCount: 1,
          });
        }
      });
      let newInspectionRecords = [];
      scopes.forEach((s) => {                // 把记录按scope顺序和EquipmentId顺序放到新数组里
        inspectionRecords.forEach((r) => {
          if(r.scope === s.scopeName) {
            newInspectionRecords.push(r);
          }
        });
      });

      // todo: 这里如果按照scope排序来返回，前端的数据就无法控制顺序
      // inspectionRecords.sort((a, b) => {  // 先按照scope排序
      //   return a.scope > b.scope ? 1 : -1;
      // });
      // let scopes = [];
      // let scope;
      // inspectionRecords.forEach((record) => {
      //   if(scope !== record.scope) {  // 由于已经按照scope排序，如果不同了，说明要加一个新的scope
      //     scope = record.scope;
      //     scopes.push({
      //       scopeName: scope,
      //       scopeCount: 1,
      //     });
      //   } else {
      //     scopes[scopes.length - 1].scopeCount += 1;
      //   }
      // });

      ctx.body = {
        code: 0,
        msg: {
          createdAt: file.createdAt,
          daySignatory: file.daySignatory,
          nightSignatory: file.nightSignatory,
          superSignatory: file.superSignatory,

          d1Signatory: file.d1Signatory,
          d2Signatory: file.d2Signatory,
          d3Signatory: file.d3Signatory,
          d4Signatory: file.d4Signatory,
          d5Signatory: file.d5Signatory,
          d6Signatory: file.d6Signatory,
          d7Signatory: file.d7Signatory,

          n1Signatory: file.n1Signatory,
          n2Signatory: file.n2Signatory,
          n3Signatory: file.n3Signatory,
          n4Signatory: file.n4Signatory,
          n5Signatory: file.n5Signatory,
          n6Signatory: file.n6Signatory,
          n7Signatory: file.n7Signatory,

          abnormalRecord: file.abnormalRecord,
          totalCount: newInspectionRecords.length,
          count: newInspectionRecords.length,
          inspectionRecords: newInspectionRecords,
          scopes: scopes,
        }
      }
    } else {
      ctx.body = {
        code: 10,
        msg: {
          error: '请求接口错误',
        }
      };
      return;
    }
  }

  async updateInspectionData(ctx) {
    let { id, equipmentState } = ctx.request.body;
    let record = await InspectionRecord.findOne({
      where: {
        id,
      },
      include: [{
        model: InspectionFile,
      }, {
        model: EquipmentAttribute,
        include: {
          model: Equipment,
        }
      }]
    });
    let oid = record.InspectionFile.oid;
    let EquipmentId = record.EquipmentAttribute.Equipment.id;

    await InspectionRecord.update({  // 先update再检查是否要将检查单置为正常或异常
      state: equipmentState,
    }, {
      where: {
        id,
      }
    });

    if( equipmentState === 1 ) {  // 如果是有异常，修改巡视检查单为不正常，将设备改成故障
      await InspectionFile.update({
        isAbnormal: true,
      }, {
        where: {
          oid,
        }
      });
      await Equipment.update({
        state: false,
      }, {
        where: {
          id: EquipmentId,
        }
      });
    } else if( equipmentState === 0 ) {  // 如果是变正常，检查此检查单是否还有state为1的记录，如果没有，则改成正常
      let abnormalRecord = await InspectionRecord.findOne({
        where: {
          InspectionFileOid: oid,
          state: 1,
        }
      });
      console.log('abnormal', abnormalRecord);
      if(!abnormalRecord) {
        await InspectionFile.update({
          isAbnormal: false,
        }, {
          where: {
            oid,
          }
        });
      }
    }

    ctx.body = {
      code: 0,
      msg: {},
    }
  }

  async addAbnormalRecord(ctx) {
    let { oid, abnormalRecord } = ctx.request.body;
    await InspectionFile.update({
      abnormalRecord,
    }, {
      where: {
        oid
      },
    });

    ctx.body = {
      code: 0,
      msg: {},
    }
  }

  async confirmRecord(ctx) {
    let { oid, sign, type, signWeekday } = ctx.request.body;
    // todo: signWeekday must be integer
    signWeekday = signWeekday || 1;
    if(typeof signWeekday !== 'number') {
      ctx.body = {
        code: 101,
        msg: {
          error: '参数错误'
        }
      };
      return;
    }
    let BrowsePrivileges = ctx.user.Department.BrowsePrivilege;
    if( BrowsePrivileges['inspectionSupport']) {  // 如果是博维Support人员
      await InspectionFile.update({
        superSignatory: sign,
      }, {
        where: {
          oid,
        }
      });
    } else if(type === 'day' ) {  // 如果是白班人员
      let newValue = {};
      newValue.daySignatory = sign;
      newValue[`d${signWeekday}Signatory`] = sign;
      await InspectionFile.update(newValue, {
        where: {
          oid,
        }
      });
    } else if( type === 'night' ) {  // 如果是夜班人员
      let newValue = {};
      newValue.nightSignatory = sign;
      newValue[`n${signWeekday}Signatory`] = sign;
      await InspectionFile.update(newValue, {
        where: {
          oid,
        }
      });
    }

    ctx.body = {
      code: 0,
      msg: {},
    }
  }
}

module.exports = new InspectionController();
